Skip to content

chore: add intercom (IN-1028)#3945

Merged
joanagmaia merged 4 commits intomainfrom
chore/add-intercom
Mar 24, 2026
Merged

chore: add intercom (IN-1028)#3945
joanagmaia merged 4 commits intomainfrom
chore/add-intercom

Conversation

@joanagmaia
Copy link
Contributor

@joanagmaia joanagmaia commented Mar 23, 2026

This pull request introduces Intercom integration into the frontend application, enabling user-specific Intercom chat support based on authentication state. The main changes include configuration additions, dynamic script loading and lifecycle management for Intercom, and hooks into the authentication flow to boot and shut down Intercom as users log in or out.

Intercom Integration

  • Added Intercom configuration to environment variables and application config, including appId, API base, and Auth0 claim keys for user identification. [1] [2] [3]
  • Implemented a new utility module frontend/src/utils/intercom/index.ts to handle dynamic loading, booting, updating, and shutdown of the Intercom widget, with support for JWT-based identity verification.

Authentication Flow Updates

  • Updated authentication actions to boot Intercom with user details and JWT after login, and to shut down Intercom on logout, ensuring proper lifecycle management tied to user sessions. [1] [2] [3]

Note

Medium Risk
Medium risk because it introduces a third-party script load and session-coupled boot/shutdown using Auth0 claims/JWTs; misconfiguration could impact login flows or leak user identifiers to Intercom.

Overview
Adds an Intercom integration to the frontend, including a new config.intercom section (app id, API base, and Auth0 claim keys) and wiring VUE_APP_INTERCOM_APP_ID through local env defaults and the docker runtime env-var replacement.

Hooks Intercom into the auth lifecycle: on authenticated header setup it boots Intercom with user identity + intercom_user_jwt (from Auth0 claims), and on logout it shuts Intercom down. A new utils/intercom module handles dynamic script injection, queued boot/update calls, timeouts, and cleanup of JWT settings.

Written by Cursor Bugbot for commit 86c4374. This will update automatically on new commits. Configure here.

Signed-off-by: Joana Maia <jmaia@contractor.linuxfoundation.org>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Intercom to the frontend and wires it into the auth lifecycle so the widget boots for authenticated users and shuts down on logout.

Changes:

  • Added Intercom configuration (env + app config) including Auth0 claim keys.
  • Introduced an Intercom utility for script loading + boot/update/shutdown.
  • Hooked Intercom boot/shutdown into the authentication flow (login/logout).

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 7 comments.

File Description
frontend/src/utils/intercom/index.ts New Intercom loader/boot/update/shutdown utility module.
frontend/src/modules/auth/store/auth.actions.ts Boots Intercom after login and shuts it down on logout.
frontend/src/config.js Adds intercom config (appId, api base, Auth0 claim keys).
frontend/.env.dist.local Adds a distribution env var for Intercom app id.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +91 to +95
// Set JWT in intercomSettings before boot — required for identity verification
if (options.intercom_user_jwt) {
window.intercomSettings = window.intercomSettings || {};
window.intercomSettings.intercom_user_jwt = options.intercom_user_jwt;
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

intercom_user_jwt is stripped out of the payload passed to Intercom('boot', ...). If identity verification relies on providing intercom_user_jwt in the boot call (as Intercom’s standard flow does), this can lead to users being booted without verification. Include intercom_user_jwt in the boot payload (or pass window.intercomSettings as the boot object after merging user fields) so verification is reliably applied.

Copilot uses AI. Check for mistakes.
Comment on lines +111 to +115
const { intercom_user_jwt: _jwt, ...bootOptions } = options;
window.Intercom('boot', {
api_base: config.intercom.apiBase,
app_id: config.intercom.appId,
...bootOptions,
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

intercom_user_jwt is stripped out of the payload passed to Intercom('boot', ...). If identity verification relies on providing intercom_user_jwt in the boot call (as Intercom’s standard flow does), this can lead to users being booted without verification. Include intercom_user_jwt in the boot payload (or pass window.intercomSettings as the boot object after merging user fields) so verification is reliably applied.

Suggested change
const { intercom_user_jwt: _jwt, ...bootOptions } = options;
window.Intercom('boot', {
api_base: config.intercom.apiBase,
app_id: config.intercom.appId,
...bootOptions,
window.Intercom('boot', {
api_base: config.intercom.apiBase,
app_id: config.intercom.appId,
...options,

Copilot uses AI. Check for mistakes.
Comment on lines +74 to +78
if (!config.intercom.appId) {
console.info('Intercom: Disabled (no appId configured)');
reject(new Error('No Intercom app ID configured'));
return;
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Treating “Intercom disabled by configuration” as a rejected Promise forces callers to handle this as an error path, even though it’s an expected state. Prefer resolving as a no-op when appId is missing (and/or exposing an isEnabled() helper) so downstream auth flows don’t need to special-case this.

Copilot uses AI. Check for mistakes.
Comment on lines +55 to +58
script.onerror = (error) => {
isLoading = false;
console.error('Intercom: Failed to load script', error);
};
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the script fails quickly (onerror), boot() will still poll for up to 10s before rejecting, which delays auth lifecycle completion and adds avoidable background work. Consider making loadScript() return a shared Promise (cached across calls) that resolves on onload and rejects on onerror, and have boot() await that instead of polling; this will fail fast, simplify control flow, and avoid repeated intervals/timeouts for concurrent boots.

Copilot uses AI. Check for mistakes.
Comment on lines +97 to +132
const checkLoaded = setInterval(() => {
if (isLoaded && window.Intercom) {
clearInterval(checkLoaded);
clearTimeout(timeoutHandle);

if (isBooted) {
const { intercom_user_jwt: _jwt, ...updateOptions } = options;
update(updateOptions);
resolve();
return;
}

isBooted = true;
try {
const { intercom_user_jwt: _jwt, ...bootOptions } = options;
window.Intercom('boot', {
api_base: config.intercom.apiBase,
app_id: config.intercom.appId,
...bootOptions,
});
resolve();
} catch (error) {
isBooted = false;
console.error('Intercom: Boot failed', error);
reject(error);
}
}
}, 100);

const timeoutHandle = setTimeout(() => {
clearInterval(checkLoaded);
if (!isBooted) {
isLoading = false;
reject(new Error('Intercom script failed to load'));
}
}, 10000);
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the script fails quickly (onerror), boot() will still poll for up to 10s before rejecting, which delays auth lifecycle completion and adds avoidable background work. Consider making loadScript() return a shared Promise (cached across calls) that resolves on onload and rejects on onerror, and have boot() await that instead of polling; this will fail fast, simplify control flow, and avoid repeated intervals/timeouts for concurrent boots.

Copilot uses AI. Check for mistakes.
email: user.email,
intercom_user_jwt: intercomJwt,
}).catch((error: any) => {
console.error('Intercom: Boot failed', error);
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logging the raw error object can inadvertently include sensitive context (depending on how errors are produced/serialized), and this path is triggered during authentication. Prefer logging a sanitized message (e.g., error?.message) and avoid dumping full objects that might contain user identifiers or token-related info.

Suggested change
console.error('Intercom: Boot failed', error);
console.error('Intercom: Boot failed:', (error && error.message) ? error.message : String(error));

Copilot uses AI. Check for mistakes.
VUE_APP_CONVERSATIONS_PUBLIC_URL=http://localhost:3000
VUE_APP_NANGO_URL=http://localhost:3003
VUE_APP_ENV=local
VUE_APP_INTERCOM_APP_ID=mxl90k6y
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.env.dist.local is typically a template; committing a concrete app id can cause accidental usage against the wrong Intercom workspace in local/dev setups. Consider leaving this blank or using an obvious placeholder value (with a short comment) to encourage explicit configuration per environment.

Suggested change
VUE_APP_INTERCOM_APP_ID=mxl90k6y
# Set your Intercom app id for this environment (leave blank if not used).
VUE_APP_INTERCOM_APP_ID=

Copilot uses AI. Check for mistakes.
Signed-off-by: Joana Maia <jmaia@contractor.linuxfoundation.org>
boot,
update,
shutdown,
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exported useIntercom composable is never used

Low Severity

The useIntercom composable is exported but never imported anywhere in the codebase. The auth actions module directly imports boot and shutdown instead. This is dead code that adds unnecessary surface area to the module.

Fix in Cursor Fix in Web

gaspergrom
gaspergrom previously approved these changes Mar 24, 2026
Signed-off-by: Joana Maia <jmaia@contractor.linuxfoundation.org>
console.error('Intercom: Shutdown failed', error);
}
}
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shutdown doesn't cancel a pending boot operation

Low Severity

shutdown() only acts when isBooted is true, but if it's called while boot() is still waiting for the script to load (polling via setInterval), the pending interval is never cleared. Once the script finishes loading, the interval callback will still execute and boot Intercom with the previous user's credentials. Adding a cancellation flag (e.g., a cancelled boolean checked inside the interval) would close this lifecycle gap.

Additional Locations (1)
Fix in Cursor Fix in Web

Signed-off-by: Joana Maia <jmaia@contractor.linuxfoundation.org>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 3 total unresolved issues (including 2 from previous reviews).

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

api_base: config.intercom.apiBase,
app_id: config.intercom.appId,
...bootOptions,
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JWT stripped from Intercom boot call breaks verification

High Severity

The intercom_user_jwt is explicitly destructured out and excluded from the options passed to window.Intercom('boot', ...). It's only set on window.intercomSettings, but Intercom's boot API call uses its own argument object — not window.intercomSettings — for identity verification. Per Intercom's SPA documentation, the JWT must be passed directly in the boot call for authenticated sessions to work. Without it, identity verification will silently fail and users won't get an authenticated Intercom experience.

Additional Locations (1)
Fix in Cursor Fix in Web

@joanagmaia joanagmaia merged commit 8a05d36 into main Mar 24, 2026
15 checks passed
@joanagmaia joanagmaia deleted the chore/add-intercom branch March 24, 2026 18:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants